/*
    <one line to give the library's name and an idea of what it does.>
    Copyright (C) 2013  Guillaume <email>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/


#ifndef MSELEMENT_H
#define MSELEMENT_H

#include <msTreeMapper.h>
#include <Eigen/Dense>
#include <msUnitsManager.h>

namespace atomism
{
using namespace Eigen;
 

class msElement : public msTreeMapper 
{
    friend class msEntity;
    friend class msSystem;

private:
    //!\name from msRegister 
    //@{
    static msRegistrar Registrar;
    static bool  isElementRegisteredInPython;
    static msRegister* createInstance() { return new msElement; }
    //@}
public:
  
    static boost::shared_ptr<msElement> New()
          {boost::shared_ptr<msElement> T( new msElement );
	   T->initialize();
	   return T;
	   }

    static boost::shared_ptr<msElement> New(msUnit& massUnit)
          {boost::shared_ptr<msElement> T( new msElement );
	   T->initialize();
	   return T;
	   }
	   
    virtual boost::shared_ptr<msTreeMapper> clone() { 
            boost::shared_ptr<msElement> clone = New(); 
	    clone->msTreeMapper::operator=(*this);					      
	    return clone;
            }
  
protected:
   
    msElement() : msTreeMapper() { 
           constructVar("msElement","Element","element");
           };
	   
    void initialize()  { 
             msTreeMapper::initialize();
            // declareAttribute(Mass,"Mass");
             };
	     
    void registryInPython();
    

    void setMass(double m, msUnit& unit) { 
  
      Mass = m; MassUnit = unit; 
    };

public:
           
    virtual double getMass(msUnit::uMass unit) const {return Mass;};
    
    Vector3d getPosition() const {return Position;}

    double getX() const {return Position[0];}
    double getY() const {return Position[1];}
    double getZ() const {return Position[2];}
    
    bool setPosition(double x,double y,double z) { 

          if( (x!=x) || (y!=y) || (z!=z) ){ 
	    
              Position<<0,0,0;
	      throw msError("Nan providen to msElement" , "bool msElement::setPosition(double x,double y,double z)" , getFullId());
              }
          Position<<x,y,z; return 1;
          }
    
    bool setPosition(Vector3d pos) { return setPosition(pos[0],pos[1],pos[2]); };
    
    void applyTranslation(const Vector3d& v) { if( (v[0]!=v[0]) || (v[1]!=v[1]) || (v[2]!=v[2]) )
						  throw msError("Nan providen to msElement" , "void msElement::applyTranslation(const Vector3d& v)" , getFullId());
					       Position+=v; 
				              }
    
    void applyTransformation(const Matrix3d& mat){Position=mat*Position;};
    
private:
           
    msUnit MassUnit;

    Vector3d Position;
    
    double Mass;
    
};

}
#endif // MSELEMENT_H
